home *** CD-ROM | disk | FTP | other *** search
- /*
- #-------------------------------------------------------------------------------------------
- #
- # Program: < DMZ 1.5 >
- # File: < dmzOT.c >
- #
- # by Rich Kubota
- # of <Apple Macintosh Developer Technical Support - or wheverever>
- #
- # Modification History
- # 4/24/96 rrk Added raw mode support under OT so that we can access the full DDP
- # header info - like the hop count field. This technique also allows
- # one to fill out the DDP packet header themselves and have the packet
- # transmitted as is. Unfortunately, this technique will not work for trying
- # to transmit a packet with a DDP type of 0.
- #
- # 6/14/94 rrk Added OpenTransport support to DMZ
- #
- #-------------------------------------------------------------------------------------------
- */
-
- /*
- * dmz Sample OpenTransport Stuff
- *
- * This unit provides OpenTansport AppleTalk support for dmz.
- * These functions are similar to many of those provided in the dmzAT.c file.
- */
-
- #include "dmz.h"
-
- // static globals here
- static ATSvcRef gOTSvcRef = nil;
- static MapperRef gOTMapper = nil;
- static EndpointRef gOTEndpoint = nil;
- static OTNameID gMyNameID = 0;
- static UInt32 gNBPLookupOutstanding = 0;
- static TLookupRequest gLookupRequest;
- static TLookupReply gLookupReply;
-
- static NBPEntity gNBPEntity;
- static OTResult gLookupResult;
-
- static long gNotifyFlag;
- static long gStartTicks;
- static long gEndTicks;
- static OTEventCode gNotifyCode;
- static OSStatus gNotifyErr;
- static void* gOKAckMsg = NULL;
- static void* gNotifyCookie;
- static OSStatus gErrorAckMsg = kOTNoError;
-
-
- /* globals from afar */
- /* out main dialog */
- extern DialogPtr gLookupDialog;
- extern DialogPtr gMyDialog;
- extern char gNameGlob[34];
- extern SysEnvRec GMAC;
- extern short gATalkFlags;
-
- // out of the dmzAT file
- extern PacketBuffer gBuffers[kNumBuffers]; /* set up by InitEchoBuffers */
- extern QHdr gFreeQ, gUsedQ; /* set up by InitEchoBuffers */
- extern Handle gSockCodeHndl; /* handle to socket listener code resource */
- extern Ptr gBuffPtr;
- extern myMPPParamBlock *gPBLkUP;
- extern Boolean gUpdateListFlag;
- extern Boolean gLookupFinished;
- extern NamesTableEntry gMyNTE;
- extern AddrBlock gTheBridgeAddress;
- extern Boolean gHasPhase2;
-
- extern Ptr GTHEVBLPTR;
- extern Ptr GTHETASKPTR;
-
- // globals referenced from dmzLists.c
- extern ListHandle gZonesList, gObjectTypeList;
-
-
- /************************* local prototypes *************************/
- static short clen(char *cptr);
- static void c2p(char *cptr);
- /********************************************************************/
- static OSStatus DoBindDDPEndpoint(EndpointRef ep, DDPAddress *retAddr);
- static pascal void HandleEndpointEvents(void* contextPtr, OTEventCode code,
- OTResult result, void* it);
- static OSStatus ReadData(EndpointRef ep, UInt8 *buffer, short buflen);
- static Boolean CanDoRawMode(EndpointRef ep);
- static void DoValueBreak(long value, const char* message);
-
- /*
- * CheckOpenTransportActive checks whether ASLM is available using
- * InitLibraryManager. If successful, then set the flag
- * to indicate so
- */
-
- OSErr ActivateOpenTransport(void)
- {
- OSErr err;
- OSStatus oserr = kOTNoError;
-
- err = InitOpenTransport();
-
- // open the appletalk services provider
- if (err == noErr)
- gOTSvcRef = OTOpenAppleTalkServices(OTCreateConfiguration(kZIPName), 0, &oserr);
-
- // open an NBP Mapper service provider
- if ((err == noErr) && (oserr == kOTNoError))
- gOTMapper = OTOpenMapper(OTCreateConfiguration(kNBPName), 0, &oserr);
-
- if ((err == noErr) && (oserr == kOTNoError))
- {
- // install notifier for the mapper
- // note that since OpenTransport sets the A5 world for a handler,
- // we don't need to mess with saving/setting/restoring A5 - yea!!
- oserr = OTInstallNotifier(gOTMapper, (OTNotifyProcPtr)MyDMZNBPHandler, nil);
- }
-
- // open an endpoint ref
- if ((err == noErr) && (oserr == kOTNoError))
- {
- // set up the endpoint
- gOTEndpoint = OTOpenEndpoint(OTCreateConfiguration(kDDPName), 0, nil, &oserr);
- if (oserr == kOTNoError)
- {
- // install asynchronous notifier
- OTInstallNotifier(gOTEndpoint, HandleEndpointEvents, &gNotifyFlag);
- }
- }
-
- if ((err == noErr) && (oserr == kOTNoError))
- { // if ASLM init'd ok, then the
- // associated Open Transport libs were found
- SetOTActiveFlag(gATalkFlags); // indicate OpenTransport is active
- gHasPhase2 = true; // we have phase 2
- }
- else // error occurred somewhere
- {
- if (gOTSvcRef)
- {
- OTCloseProvider(gOTSvcRef);
- gOTSvcRef = nil;
- }
- if (gOTMapper)
- {
- OTCloseProvider(gOTMapper);
- gOTMapper = nil;
- }
- if (gOTEndpoint)
- {
- OTCloseProvider(gOTEndpoint);
- gOTEndpoint = nil;
- }
- }
-
- if (err != noErr)
- return err;
- else
- return oserr;
- }
-
- /*
- * OpenTransportActive simplifies checking the global flag to see whether
- * the OTActive flag is set. This could also be a macro
- */
-
- Boolean OpenTransportActive(void)
- {
- return (TstOTActiveFlag(gATalkFlags));
- }
-
- /*
- * GetBridgeAddressFromOT uses OpenTransport to determine whether
- * there is a router on the network
- */
-
- typedef struct AppleTalkInfo AppleTalkInfo;
-
- void GetBridgeAddressFromOT(AddrBlock *theAddr)
- {
- AppleTalkInfo info;
- TNetbuf reply;
- OSErr err;
-
- // set reply values
- reply.buf = (UInt8*)&info;
- reply.len = reply.maxlen = sizeof(info);
-
- err = OTATalkGetInfo(gOTSvcRef, &reply);
- if (err != noErr)
- {
- DebugStr("\pError returned from OTATalkGetInfo");
- theAddr->aNet = 0;
- theAddr->aNode = 0;
- theAddr->aSocket = 0;
- }
- else
- {
- theAddr->aNet = info.fRouterAddress.fNetwork;
- theAddr->aNode = info.fRouterAddress.fNodeID;
- theAddr->aSocket = info.fRouterAddress.fSocket;
- }
- }
-
- /*
- * DoOTGetMyZone uses OpenTransport to determine what
- * the current zone is
- */
- void DoOTGetMyZone(char *myZoneBuffer)
- {
- TNetbuf reply;
- OSErr err;
-
- reply.buf = (UInt8*)myZoneBuffer;
- //reply.len = 0;
- reply.maxlen = sizeof(Str32);
- err = OTATalkGetMyZone(gOTSvcRef, &reply);
- if (err != noErr)
- myZoneBuffer[0] = 0;
- }
-
- /*
- * DoOTGetZoneList uses OpenTransport to determine whether
- * there is a router on the network
- */
- void DoOTGetZoneList(void)
- {
- TNetbuf reply;
- OSErr err = 0;
- Ptr unpackedBufferPtr, packedBufferPtr;
- short numZones;
-
- // need two buffers to hold the zone names
- // 1 to give to the OTZoneList call to fill in a packed list of zone names
- // 2 to unstuff the zones names and pass to the SetZoneCells call
- packedBufferPtr = NewPtr(kMaxZoneBuffSize); /* size of maxstring size * 255 zones */
- unpackedBufferPtr = NewPtr(kMaxZoneBuffSize); /* size of maxstring size * 255 zones */
- if (packedBufferPtr != nil && unpackedBufferPtr != nil)
- {
- reply.buf = (UInt8*)packedBufferPtr;
- reply.maxlen = kMaxZoneBuffSize; // under OT, the buffer for the zone names can be greater than 32767
- // however since we are passing the buffer to the List Manager
- // we limit the size to max SInt16
-
- // set service ref for synch mode
- OTSetSynchronous(gOTSvcRef);
-
- err = OTATalkGetZoneList(gOTSvcRef, &reply);
-
- if (err != kOTNoError && err != kOTNoDataErr)
- BigBadError("\pOTGetZoneList returned err - Aborting program!!");
- else
- {
- // unpack the zone names into the unpackedBuffer
- numZones = addToOTUnpackedBuffer(packedBufferPtr, unpackedBufferPtr, reply.len);
- // set the zone names in the zone cells
- SetZoneCells(unpackedBufferPtr, numZones);
- }
- }
- else
- {
- BigBadError("\pError getting memory for GetZoneList call - Aborting program!!");
- }
-
-
- }
-
- void CleanupOTServices(void)
- {
- // close AppleTalk Services
- OTCloseProvider(gOTSvcRef);
- // close the mapper
- OTCloseProvider(gOTMapper);
- // close the endpoint
- OTCloseProvider(gOTEndpoint);
- ClrOTLookupActiveFlag(gATalkFlags); // clear the OTActive flag
- }
-
-
- /*
- * in order for us to use the standard qsort() algorithm, our data must be alligned in
- * an orderly fashion with a set offset from each data entry. This routine takes care of
- * that through simple _BlockMove manipulations. Note that this routine is a modification
- * of the addToUnpackedBuffer routine in that it assumes that all of the names are in
- * the unpacked buffer. Instead of the number of zones, we only know the number of
- * valid bytes in the buffer. We also determine the number of zones and return this
- * info to the caller.
- */
- short addToOTUnpackedBuffer(Ptr packedBuffer, Ptr unpackedBuffer, long len)
- {
- long index = 0L;
- short i = 0;
-
- while ((index < len) && (index < kMaxZoneBuffSize - 32))
- {
- BlockMove((Ptr)packedBuffer+index, (Ptr)unpackedBuffer+i*33, 33L);
- index += (char)((Ptr)packedBuffer+index)[0]+1L;
- i++;
- }
- return i;
- }
-
- /*******************************************************************************
- ** Register my name using Open Transport
- ********************************************************************************/
- void OTRegisterMyName (void)
- {
- TRegisterRequest regreq;
- TRegisterReply regreply;
- StringHandle userNameHndl;
- OSErr err;
- UInt8 nameBuf[100];
-
- // for registering a name, we'll first try to get the flagship name
- // otherwise, we'll use the machinename
- userNameHndl = GetString(kFlagshipNameResourceID);
- if (**userNameHndl == 0)
- {
- userNameHndl = GetString(kMachineNameResourceID);
- if(**userNameHndl == 0)
- {
- userNameHndl = (StringHandle)NewHandle(32);
- if (userNameHndl)
- BlockMove("\pYour name here.", *userNameHndl, 15L);
- }
-
- }
- // create the NBP name string and set the len field for the string
- regreq.name.len = OTMySetNBPEntity((char*)nameBuf, (Ptr)*userNameHndl, (Ptr)kEchoType, (Ptr)"\p*");
- regreq.name.maxlen = sizeof(nameBuf);
- regreq.name.buf = nameBuf;
-
- // let the system define the network address for this name
- regreq.addr.len = regreq.addr.maxlen = 0;
- regreq.addr.buf = NULL;
-
- // set up regreply
- regreply.addr.maxlen = 0;
- regreply.addr.buf = nil;
-
- OTSetSynchronous(gOTMapper);
- err = OTRegisterName(gOTMapper, ®req, ®reply);
- gMyNameID = regreply.nameid;
- }
-
- /*******************************************************************************
- ** Delete my name using Open Transport
- ********************************************************************************/
- void OTDeleteMyName (void)
- {
- OTSetSynchronous(gOTMapper);
- OTDeleteNameByID(gOTMapper, gMyNameID);
- }
-
- /*******************************************************************************
- ** HandleMapperEvents TMapper (NBP) Event Handling
- ********************************************************************************/
-
- pascal void MyDMZNBPHandler(void* contextPtr, OTEventCode event, OTResult result, void* cookie)
- {
-
- switch (event)
- {
- case T_LKUPNAMERESULT: // intermediate result notification
- break;
-
- case T_LKUPNAMECOMPLETE:
- gUpdateListFlag = true;
- // clear bit which indicates that we are doing a lookup
- ClrOTLookupActiveFlag(gATalkFlags);
- break;
-
- case T_REGNAMECOMPLETE:
- if (result == kOTNoError)
- {
- SetNameRegisteredFlag(gATalkFlags);
- /* if error occured registering name, there is no reason to
- * abort the program
- */
- }
- break;
-
- case T_DELNAMECOMPLETE:
- if (result == kOTNoError)
- {
- ClrNameRegisteredFlag(gATalkFlags);
- }
- break;
-
- default:
- DebugStr("\pHandleMapperEvents: Unexpected Event!;g");
- break;
- }
- }
-
- UInt16 OTMySetNBPEntity(char *buffer, Ptr nbpObject, Ptr nbpType, Ptr nbpZone)
- {
- char* bufPtr;
- UInt16 len;
-
- bufPtr = buffer;
-
- BlockMove((Ptr)&nbpObject[1], bufPtr, nbpObject[0]);
- bufPtr += nbpObject[0]; // point buffer to end of current string
- len = nbpObject[0]; // collect number of chars moved to buffer
-
- // add the ":" character between the object and type strings
- *bufPtr = ':';
- bufPtr++;
- len++;
-
- BlockMove((Ptr)&nbpType[1], bufPtr, nbpType[0]);
- bufPtr += nbpType[0]; // point buffer to end of current string
- len += nbpType[0]; // collect number of chars moved to buffer
-
- // add the "@" character between the type and zone strings
- *bufPtr = '@';
- bufPtr++;
- len++;
-
- BlockMove((Ptr)&nbpZone[1], bufPtr, nbpZone[0]);
- len += nbpZone[0]; // collect number of chars moved to buffer
- return len;
- }
-
- void DoOTNameLookup(char *NBPObject, char *NBPType, char *NBPZone)
- {
- OSErr err;
-
- // first check to see whether a Lookup is in progress
- if (TstOTLookupActiveFlag(gATalkFlags))
- return;
-
- // set the maximum number of names to match
- gLookupRequest.maxcnt = kLookupBufSize / kNBPEntityBufferSize;
- // set the timeout paramter in milliseconds
- gLookupRequest.timeout = 8000; // 8 seconds
- // set the name to look up
-
- gLookupRequest.name.len = (size_t)OTMySetNBPEntity((char*)&gNBPEntity, (Ptr)NBPObject, (Ptr)NBPType, (Ptr)NBPZone);
- // gLookupRequest.name.maxlen = gLookupRequest.name.len;
- gLookupRequest.name.buf = (UInt8*)&gNBPEntity;
-
- gLookupRequest.addr.len = 0;
- gLookupRequest.addr.maxlen = 0;
- gLookupRequest.addr.buf = nil;
-
- gLookupReply.names.maxlen = kLookupBufSize;
-
- memset(gBuffPtr, 0, kLookupBufSize); // zero out the buffer so that extraneous characters don't get left
- // in the buffer to confuse the name parsing routines which are looking
- // for null terminated strings.
- gLookupReply.names.buf = (UInt8*)gBuffPtr;
-
- // indicate that we are doing a lookup
- gLookupFinished = false;
- // start spinning cursor
- StartAnimatedCursors(kSpinEvery5Ticks, 15);
-
- // make the call asynchronously
- OTSetAsynchronous(gOTMapper);
- err = OTLookupName(gOTMapper, &gLookupRequest, &gLookupReply);
- // indicate that a lookup call is active.
- SetOTLookupActiveFlag(gATalkFlags);
-
- }
-
- void ProcessOTListUpdate(char *resultStr)
- {
- Str255 errorStr;
-
- if (gLookupResult == noErr)
- {
- NumToString((long)gLookupReply.rspcount, (StringPtr)resultStr);
- Pstrcat((StringPtr)resultStr, "\p items");
-
- // set the cells of the list
- OTSetObjectTypeCells(gBuffPtr, gLookupReply.rspcount);
- }
- else
- {
- NumToString((long)gLookupResult, errorStr);
- resultStr[0] = 0;
- Pstrcat((StringPtr)resultStr, "\pError ID = ");
- Pstrcat((StringPtr)resultStr, errorStr);
- }
- StopAnimatedCursors();
- }
-
- void OTSetObjectTypeCells(Ptr ptr, short numDevicesGot)
- {
- DDPNBPAddress *theNBPAddrInfo;
- NBPEntity *nbpEntity;
- Cell theCell;
- short ignore;
- short numDevicesIndex;
- short maxCells;
- GrafPtr tp;
- AddrBlock *address;
- UInt32 offset;
- UInt16 addrLen, nameLen, totalLen;
-
- unsigned char charHolder[6];
- long g;
- myNetworkEntity myNetEnt;
- Ptr newBuffer;
- UInt8 delimiter;
- char tempStr[10];
-
- /* tell the user this may take a little while... */
- /*waitAWhile = GetCursor(watchCursor);
- SetCursor(*waitAWhile);*/
-
- GetPort(&tp);
- SetPort(gMyDialog);
-
- /* make room for as many objects as we need */
- newBuffer = NewPtr(numDevicesGot*sizeof(myNetworkEntity));
- if(newBuffer == 0L)
- return;
-
- LDelRow(0, 0, gObjectTypeList); /* deletes lists's cells */
-
- LSetDrawingMode(false, gObjectTypeList); /* turn drawing off */
-
- numDevicesIndex = 0;
-
- // since the List Manager will only allow 32K entries, we need to limit the number
- // of entries that can be entered - numDevicesGot may be just too large, so we take
- // only those first n entries in the list which will fit into the list
- maxCells = numDevicesGot < (32767 / (sizeof(myNetworkEntity) + 4)) ? numDevicesGot : (32767 / (sizeof(myNetworkEntity) + 4));
-
- while(numDevicesIndex<maxCells)
- {
- SpinTheCursor();
- theCell.v = numDevicesIndex;
-
- ignore = LAddRow(1, numDevicesIndex, gObjectTypeList);
-
- // get the address and name lengths
- addrLen = ((short*)ptr)[0];
- nameLen = ((short*)ptr)[1];
-
- // set theAddr to point to the beginning of the DDPNBP structure
- theNBPAddrInfo = (DDPNBPAddress*)(ptr + 2 * sizeof(short));
-
- // set address to point to the appropriate spot in the address buffer
- address = (AddrBlock*)&theNBPAddrInfo->fNetwork;
-
- /* first move address data into "hidden" cell */
- theCell.h = 1;
- LSetCell((Ptr) address, 4, theCell, gObjectTypeList);
-
- // set the nbpEntity pointer to point to the namebuffer
- nbpEntity = (NBPEntity*)&theNBPAddrInfo->fNBPNameBuffer;
-
- /* now move object name & type into one cell */
- theCell.h = 0;
-
- /* object */
- // extract the object name from the entity which is a null terminated
- // string with the object, type, and zone name separated by the
- // ':' and '@' characters. Call OTExtractNBPCName which is a routine
- // defined here to parse the entity up to the character specified as the
- // delimiter. The offset parameter is 0 and is passed in to indicate that
- // we want to parse the object field from the beginning of the entity.
- delimiter = ':';
- offset = OTExtractNBPCName(nbpEntity, (char *)&myNetEnt.object, 0, &delimiter);
- // the name is in c string style, convert to pascal
- c2p((char *)&myNetEnt.object);
- // make sure that the string length is no longer than 32 chars
- if(myNetEnt.object[0] > 32)
- myNetEnt.object[0] = 32;
-
- /* type */
- // we do the same for the type string as we did for the object name
- // above.
- delimiter = '@';
- OTExtractNBPCName(nbpEntity, (char *)&myNetEnt.type, offset, &delimiter);
- // the name is in c string style, convert to pascal
- c2p((char *)&myNetEnt.type);
- // make sure that the string length is no longer than 32 chars
- if(myNetEnt.type[0] > 32)
- myNetEnt.type[0] = 32;
-
- /* network */
- g = (long)address->aNet;
- g = g & 0x0000FFFF; /* mask out hiword crap */
- NumToString(g, (void *) &charHolder);
- padEntry((void *) &charHolder, 5, rightJust);
- BlockMove(&charHolder, &myNetEnt.net, 6L);
-
- /* node */
- NumToString((long)address->aNode, (void *) &charHolder);
- padEntry((void *) &charHolder, 3, rightJust);
- BlockMove(&charHolder, &myNetEnt.node, 4L);
-
- /* socket */
- NumToString((long)address->aSocket, (void *) &charHolder);
- padEntry((void *) &charHolder, 3, rightJust);
- BlockMove(&charHolder, &myNetEnt.socket, 4L);
-
- BlockMove((Ptr) &myNetEnt, (Ptr)newBuffer+(numDevicesIndex)*sizeof(myNetworkEntity),
- sizeof(myNetworkEntity));
-
- LSetCell((Ptr)&myNetEnt, sizeof(myNetworkEntity), theCell, gObjectTypeList);
-
- // increment the index counter
- numDevicesIndex += 1;
- // get the total length of this NBP record
- totalLen = addrLen + nameLen + 2 * sizeof(short);
- // advance the ptr to the next record which is alligned on a 4 byte
- // boundary
- ptr = ptr + ((totalLen + 3) & ~3);
-
- }
-
- /* do a quicksort() on the mess */
- letsSort(newBuffer, numDevicesGot, sizeof(myNetworkEntity));
-
- numDevicesIndex = 0;
-
- while(numDevicesIndex<maxCells)
- {
- theCell.v = numDevicesIndex;
- theCell.h = 0;
- BlockMove((Ptr)newBuffer+(numDevicesIndex)*sizeof(myNetworkEntity), (Ptr) &myNetEnt, sizeof(myNetworkEntity));
- LSetCell((Ptr)&myNetEnt, sizeof(myNetworkEntity), theCell, gObjectTypeList);
- numDevicesIndex += 1;
- }
-
- DisposePtr(newBuffer);
-
- NumToString(numDevicesIndex, (void *) tempStr);
-
- ParamText((ConstStr255Param)tempStr, "\p# of objects: ", "\p", "\pOT active");
-
- LSetDrawingMode(true, gObjectTypeList);
- invalidateItem(8);
- invalidateItem(2);
-
- SetPort(tp);
- InitCursor();
- }
-
- /*****************************************************************************/
- /* Convert a c-string to a pascal-string. */
- short clen(char *cptr)
- {
- short i;
-
- for (i = 0; cptr[i]; ++i) {};
- return(i);
- }
-
- /*****************************************************************************/
- void c2p(char *cptr)
- {
- char len;
-
- BlockMove(cptr, cptr + 1, len = clen(cptr));
- *cptr = len;
- }
-
- /*****************************************************************************/
-
- /*
- * doOTEcho is the Open Transport version of the doEcho call. It is
- * called when the user double clicks on some item indicating
- * to send an echo packet to the echo socket on the node of that item.
- * Note that we don't use an Assembler socket listener
- *
- * Addition as of 4/24/96 - implemented the use of raw mode for sending out data so that
- * we get the return data in rawmode. This allows us to get the DDP header info.
- * Under rawmode, you create the entire packet and become responsible for sending out
- * the entire packet.
- *
- * WARNING: You must ensure that the unitdata.data.len field never exceeds 599
- * else, OT will never send the packet.
- */
- void doOTEcho(myNetworkEntity *myEnt)
- {
- DDPAddress retAddr, ddpAddr;
- KeyMap kk;
- Rect r;
- TUnitData unitdata;
- Ptr myRawBuffer = nil;
- long myWaitTicks;
- DialogPtr echoDialog;
- Handle h;
- GrafPtr savedPort;
-
- long tempL;
- OSStatus err = kOTNoError;
- OTResult result;
-
- UInt16 rawDataSize;
- UInt16 numHops;
-
- RawDPPPacketPtr rawddpPtr;
-
- short itemHit;
- short kind;
-
- UInt8 recvBuf[ddpMaxRawData+1];
- Str255 str;
-
- char noHopStr[2] = "\p?";
-
- /*
- the following are OTData related stuff
- */
- OTData otdata[3];
-
- UInt8 buf1[64] = "\001This is a sample string to send as the first part of the buffer";
- ///123456789012345678901234567890123456789012345678901234567890123
- UInt8 buf2[64] = "This is a another sample string to send as the first part buffer";
-
- Boolean gotEcho = false;
- Boolean epBound = false;
- Boolean done = false;
- Boolean useRawMode;
-
- GetPort(&savedPort);
-
- // set up the ddpAddr structure of the node which we want to
- // send our echo test packet to.
- ddpAddr.fAddressType = AF_ATALK_DDP;
-
- // set the network number
- StringToNum((StringPtr) myEnt->net, (long *) &tempL);
- ddpAddr.fNetwork = tempL;
-
- // set the node number
- StringToNum((StringPtr) myEnt->node, (long *) &tempL);
- ddpAddr.fNodeID = tempL;
-
- // set the socket field to the echo socket
- ddpAddr.fSocket = 4;
-
- // indicate that the packet is an echo DDP packet
- ddpAddr.fDDPType = 4;
-
- // get the dialog which we use to display the results
- echoDialog = GetNewDialog(131, 0L, (WindowPtr) -1L);
- SetPort(echoDialog);
-
- TextFont(geneva);
- TextSize(9);
-
- setupEchoDialog(echoDialog, myEnt);
-
- // Bind shall be handled synchronously.
- OTSetSynchronous(gOTEndpoint);
-
-
- if (err == kOTNoError)
- {
- // get the current endpoint state
- result = OTGetEndpointState(gOTEndpoint);
- if (result == T_UNBND)
- {
- // set up the reqAddr to point to the local echo socket
- err = DoBindDDPEndpoint(gOTEndpoint, &retAddr);
-
- if (err != kOTNoError)
- {
- GetDialogItem(echoDialog, 6, &kind, &h, &r);
- SetDialogItemText(h, "\pWah… Bind error occurred #");
- }
- else
- epBound = true;
- }
- }
-
- // check if the endpoint supports the raw mode so that we get the header info along with the
- // datagram
- useRawMode = CanDoRawMode(gOTEndpoint);
-
- // use rawmode unless the user has held down the option key
- if (useRawMode == true)
- {
- GetKeys(kk);
- if ((kk[1] & 0x0004) == true)
-
- useRawMode = false;
- }
-
- if (useRawMode == true)
- {
- // allocate a buffer to send message
- myRawBuffer = NewPtr(sizeof(RawDDPPacket));
- if (myRawBuffer == nil)
- {
- GetDialogItem(echoDialog, 6, &kind, &h, &r);
- SetDialogItemText(h, "\pWah… Out of mem error");
- err = memFullErr;
- }
- else
- {
- rawddpPtr = (RawDPPPacketPtr)myRawBuffer;
- // use the following to specify the maimum packet size
- // the problem is that if you declare an array of 599 bytes, the size of function
- // returns 600 which will result in the packet never being sent.
- rawDataSize = sizeof(RawDDPPacket) > ddpMaxRawData ? ddpMaxRawData : sizeof(RawDDPPacket);
- }
- }
-
-
- if (err == kOTNoError)
- {
- // send shall be handled asynchronously.
- OTSetAsynchronous(gOTEndpoint);
- if (useRawMode == true)
- {
- //
- // packet length
- //
- rawddpPtr->data[0] = (UInt8)(rawDataSize >> 8) & 0x0003; // clear hopcount, but set the upper 2 bits of the lenth
- rawddpPtr->data[1] = (UInt8)(rawDataSize & 0x00FF);
- //
- // packet checksum
- //
- rawddpPtr->data[2] = 0; // no checksum
- rawddpPtr->data[3] = 0; // no checksum
- //
- // dest network
- //
- rawddpPtr->data[4] = (UInt8)(ddpAddr.fNetwork >> 8);
- rawddpPtr->data[5] = (UInt8)(ddpAddr.fNetwork & 0x00FF);
- //
- // src network
- //
- rawddpPtr->data[6] = (UInt8)(retAddr.fNetwork >> 8);
- rawddpPtr->data[7] = (UInt8)(retAddr.fNetwork & 0x00FF);
-
- rawddpPtr->data[8] = (UInt8)ddpAddr.fNodeID; // dest node
- rawddpPtr->data[9] = (UInt8)retAddr.fNodeID; // src node
-
- rawddpPtr->data[10] = (UInt8)ddpAddr.fSocket; // set dest socket to echo socket
- rawddpPtr->data[11] = (UInt8)retAddr.fSocket; // src socket
-
- rawddpPtr->data[12] = (UInt8)ddpAddr.fDDPType; // set packet type to echo packet
-
- BlockMove((Ptr)&buf1, (Ptr)&rawddpPtr->data[13], sizeof(buf1));
-
- // set up the unitdata structure
- unitdata.udata.buf = (UInt8*)myRawBuffer; // data area
- unitdata.udata.len = rawDataSize;
- unitdata.addr.buf = nil; // address area
- unitdata.addr.len = (size_t)0xffffffffUL;
- unitdata.opt.buf = nil;
- unitdata.opt.len = 0; // no options being sent
-
- }
- else
- {
- // demonstrate use of kNetbufDataIsOTData use of buffers
-
- // set up the OTData[0] structure
- otdata[0].fNext = &otdata[1];
- otdata[0].fData = &buf1;
- otdata[0].fLen = sizeof(buf1);
-
- // set up the OTData[1] structure
- otdata[1].fNext = &otdata[2];
- otdata[1].fData = &buf2;
- otdata[1].fLen = sizeof(buf2);
-
- // set up the OTData[2] structure - the end of the list
- otdata[2].fNext = nil;
- otdata[2].fData = nil;
- otdata[2].fLen = 0;
-
- // set up unitdata fields
- unitdata.udata.buf = (UInt8*)otdata; // data area
- unitdata.udata.len = kNetbufDataIsOTData;
- unitdata.addr.buf = (UInt8*)&ddpAddr; // address area
- unitdata.addr.len = kDDPAddressLength;
- unitdata.opt.len = 0; // no options being sent
- }
-
-
- result = OTDontAckSends(gOTEndpoint);
- gNotifyCode = 0;
-
- gEndTicks = 0;
- gStartTicks = TickCount(); /* start the timer! */
-
- err = OTSndUData(gOTEndpoint, &unitdata);
- StartAnimatedCursors(kSpinEvery5Ticks, 15);
-
- myWaitTicks = TickCount() + 300L; /* wait 5 seconds for reply */
-
- result = OTDontAckSends(gOTEndpoint);
- if (err != kOTNoError)
- {
- GetDialogItem(echoDialog, 6, &kind, &h, &r);
- SetDialogItemText(h, "\pWah… Send error occurred #");
- }
-
- if (err == kOTNoError)
- {
- //
- // It's very important that we read the data while we are waiting for the "ack send" to complete.
- // DDP can use our own message to reply to us, and if we don't "read" the message, the "ackSend"
- // will never complete.
- //
- while ((done == false) && (myWaitTicks > TickCount()))
- {
- if ( gNotifyCode == T_DATA )
- {
- gNotifyCode = 0;
- while ( ReadData(gOTEndpoint, (UInt8*)&recvBuf, ddpMaxRawData) != kOTNoDataErr )
- {
- OTIdle();
- SpinTheCursor();
- }
- done = true;
- }
- SpinTheCursor();
- OTIdle();
- }
-
- if (gEndTicks != 0)
- {
-
- GetDialogItem(echoDialog, 4, &kind, &h, &r);
- if (useRawMode == true)
- {
- // if we sent the outgoing packet using raw mode, then the incoming packet will
- // be returned in raw mode.
- rawddpPtr = (RawDPPPacketPtr)&recvBuf;
- numHops = ((UInt8)rawddpPtr->data[0] & 0x3C) >> 2;
- NumToString(numHops, (void *) &str);
- SetDialogItemText(h, str);
- }
- else
- SetDialogItemText(h, (ConstStr255Param)noHopStr);
-
- GetDialogItem(echoDialog, 5, &kind, &h, &r);
- NumToString(gEndTicks - gStartTicks, (void *) &str);
- SetDialogItemText(h, str);
-
- }
- else
- {
- GetDialogItem(echoDialog, 6, &kind, &h, &r);
- SetDialogItemText(h, "\pWah… no echo reply received!");
- }
- }
- }
-
- StopAnimatedCursors();
- if (epBound == true)
- {
- err = OTUnbind(gOTEndpoint);
- }
-
- /* clean up memory allocations */
- if (myRawBuffer != nil)
- DisposePtr(myRawBuffer);
-
- /* report the results */
- centerDialog((WindowPtr) echoDialog);
-
- InitCursor();
- ShowWindow(echoDialog);
-
- ModalDialog(0L, &itemHit);
- DisposeDialog(echoDialog);
-
- SetPort(savedPort);
- }
-
- /*******************************************************************************
- ** DoBindEchoEndpoint - binds the passed endpoint ref to a DDP endpoint
- the bound address is returned in the structure pointed to by the retAddr
- parameter
- ********************************************************************************/
- OSStatus DoBindDDPEndpoint(EndpointRef ep, DDPAddress *retAddr)
- {
- DDPAddress reqAddr;
- TBind req, ret;
- OSStatus err = kOTNoError;
-
- // set up the reqAddr to point to the local echo socket
- reqAddr.fAddressType = AF_ATALK_DDP;
- reqAddr.fNetwork = 0; // set to our network
- reqAddr.fNodeID = 0; // set to our node
- reqAddr.fSocket = 0; // bind to a dynamic socket
- reqAddr.fDDPType = 0; // accept all packets to our socket;
- // bind the endpoint to the Echo socket
- req.addr.buf = (UInt8*)&reqAddr;
- req.addr.len = kDDPAddressLength;
- req.qlen = 0;
- // set up the return DDPAddress parameter if we are interested.
- // in this sample, we don't use this information
- ret.addr.buf = (UInt8*)retAddr;
- ret.addr.maxlen = sizeof(DDPAddress);
-
- err = OTBind(ep, &req, &ret);
-
- return err;
-
- }
-
- /*******************************************************************************
- ** HandleEndpointEvents
- ********************************************************************************/
-
- static pascal void HandleEndpointEvents(void* contextPtr, OTEventCode code,
- OTResult result, void* it)
- {
- switch (code)
- {
- case T_DATA:
- // set flag that some data has come in
- gNotifyCode = code;
- if ((gEndTicks == 0))
- {
- gEndTicks = TickCount();
- }
- break;
-
- case T_GETINFOCOMPLETE:
- case T_LISTEN:
- case T_CONNECT:
- case T_EXDATA:
- case T_DISCONNECT:
- case T_ORDREL:
- case T_GODATA:
- case T_GOEXDATA:
- case T_REQUEST:
- case T_REPLY:
- case T_PASSCON:
- case T_RESET:
- case T_MEMORYRELEASED:
- case T_UNBINDCOMPLETE:
- // do nothing
- break;
-
-
- default:
- DoValueBreak(code, "unknown event occurred: #");
- break;
- }
-
- }
-
- /*******************************************************************************
- ** ReadData
- ********************************************************************************/
-
- static OSStatus ReadData(EndpointRef ep, UInt8 *buffer, short buflen)
- {
- OTFlags flags = 0;
- DDPAddress theDest;
- TUnitData theData;
- OSStatus err;
-
- theData.udata.buf = buffer;
- theData.udata.maxlen= buflen;
- theData.addr.buf = (UInt8*)&theDest;
- theData.addr.maxlen = sizeof(theDest);
- theData.opt.maxlen = 0;
-
- err = OTRcvUData(ep, &theData, &flags);
-
- if ( err != kOTNoError )
- return err;
-
- return err;
- }
-
- /*
- CanDoRawMode gets the endpoint info and checks whether the T_CAN_SUPPORT_MDATA bit is
- set in the endpoint info flag field and returns true if so, false otherwise.
- */
- Boolean CanDoRawMode(EndpointRef ep)
- {
- TEndpointInfo info;
- OSStatus err;
- Boolean result;
-
- err = OTGetEndpointInfo(ep, &info);
- if (err != kOTNoError)
- result = false;
- else if (info.flags & T_CAN_SUPPORT_MDATA)
- result = true; // this also means that the src addr info is in the info record
- else
- result = false;
-
- return result;
- }
-
-
- void DoValueBreak(long value, const char* message)
- {
- static short sDoErrorBreak = 0;
-
- {
- Str255 s,
- n = "\p";
-
- s[0] = strlen(message);
- BlockMoveData(message,&s[1],s[0]);
- if (value < 0)
- {
- s[0] += 1;
- s[s[0]] = '-';
- value = -value;
- }
- while (value)
- {
- if (n[0])
- BlockMoveData(&n[1],&n[2],n[0]);
- n[0]++;
- n[1] = 48 + (value % 10);
- value /= 10;
- }
- BlockMoveData(&n[1],&s[s[0]+1],n[0]);
- s[0] += n[0];
-
- sDoErrorBreak++;
- {
- short cnt = sDoErrorBreak;
-
- s[0]++;
- s[s[0]] = ',';
- s[0]++;
- s[s[0]] = ' ';
- n[0] = 0;
- while (cnt)
- {
- if (n[0])
- BlockMoveData(&n[1],&n[2],n[0]);
- n[0]++;
- n[1] = 48 + (cnt % 10);
- cnt /= 10;
- }
- BlockMoveData(&n[1],&s[s[0]+1],n[0]);
- s[0] += n[0];
- }
- #ifdef powerpc
- SysBreakStr(s);
- #else
- DebugStr(s);
- #endif
- }
- }
-
-
-
-